#include "DatabaseConnection.h"
#include "DatabaseAccessObject.h"
#include "NotificationManager.h"
#include "FileNotificationClient.h"
#include "PlainTextNoficationComposer.h"
#include "ObjectEntity.h"
#include <vector>
#include <map>
#include <set>
#include <process.h>
#include <boost/lexical_cast.hpp>

#include <fstream>

bool isstopping = false;

void WorkingThread()
{
    //Create Notifiaction System
    std::shared_ptr<FileNotificationClient> fileNoficationClient( new FileNotificationClient( ".\\Noficiation" ) );
    NotificationManager::Instance()->Attach( fileNoficationClient );

    std::shared_ptr<NotificationComposer> composer( new PlainTextNotificationComposer );

    DataBaseAccessObject dao( "NEWSM_COL2_SQLSERVER", "sa", "Tin.netS1" );

    //For test only
    dao.QueryAlertListAutoExpandTest();
    
    while( !isstopping )
    {
        std::list< FeedObject* > feedObjectList;
        EntityManager::Instance()->GetFullFeedRuleAlertList( dao, feedObjectList );
                
        //Now we get all the feed list
        for( auto feedIt = feedObjectList.begin(); feedIt != feedObjectList.end(); ++feedIt )
        {
            //for each feed, we should start to calculate and generate the alert
            int maxAlertStatus = -1;
            FeedRuleObject* maxAlertFeedRule = NULL;
            for( auto feedRuleIt = (*feedIt)->m_feedRules.begin(); feedRuleIt != (*feedIt)->m_feedRules.end(); ++feedRuleIt )
            {
                if( (*feedRuleIt)->m_alerts.size() > 0 )
                {
                    AlertObject* latest = (*feedRuleIt)->m_alerts.back();
                    if( (*feedRuleIt)->m_alertStatus != latest->m_alertStatus )
                    {
                        //For this FeedRule pair, the alert status changed
                        (*feedRuleIt)->m_alertStatus = latest->m_alertStatus; //We should update it
                        (*feedRuleIt)->UpdateToDataBase( dao ); //Update it in database
                    }
                    if( maxAlertStatus < latest->m_alertStatus )
                    {
                        maxAlertStatus = latest->m_alertStatus;
                        maxAlertFeedRule = ( *feedRuleIt );
                    }

                    //Update all processed alert's flag
                    for( auto alit = (*feedRuleIt)->m_alerts.begin(); alit != (*feedRuleIt)->m_alerts.end(); ++alit )
                    {
                        (*alit)->m_flag = 1;
                        (*alit)->UpdateToDataBase( dao );
                    }
                }
                else
                {
                    //There is no update for this feedrule, so we use its current value
                    if( maxAlertStatus < (*feedRuleIt)->m_alertStatus )
                        maxAlertStatus = (*feedRuleIt)->m_alertStatus;
                }
            }

            if( maxAlertStatus >= 0 && maxAlertStatus != (*feedIt)->m_alertStatus ) 
            {
                //The alert status changed, so we should send out the notification
                composer->Reset();
                composer->StartConstruct();
                composer->Header();
                std::string subject("[NewsMonitoring] Feed[");
                subject += (*feedIt)->m_name;
                subject += "] AlertStatus[From ";
                subject += boost::lexical_cast<std::string>( (*feedIt)->m_alertStatus );
                subject += " To ";
                subject += boost::lexical_cast<std::string>( maxAlertStatus );
                subject += "]";

                composer->MetaData( "Subject", subject );
                composer->MetaData( "ContactAddress", (*feedIt)->m_emailList );
                composer->MetaData( "FeedName", (*feedIt)->m_name );
                composer->MetaData( "PnacPrefix", (*feedIt)->m_pnacPrefix );
                composer->MetaData( "Attribution", (*feedIt)->m_attribution );
                composer->MetaData( "AlertStatus", boost::lexical_cast<std::string>( maxAlertStatus ) );

                if( maxAlertFeedRule != NULL )
                {
                    composer->NewSection( "Messages" );
                    composer->AppendMessage( maxAlertStatus, maxAlertFeedRule->m_alerts.back()->m_message );
                    composer->EndSection();
                }
                composer->Footer();
                NotificationManager::Instance()->Notify( composer.get() );

                (*feedIt)->m_alertStatus = maxAlertStatus;
                (*feedIt)->UpdateToDataBase( dao ); //Update the database's feed alertstatus
            }
        }

        EntityManager::Instance()->Reset();//Reset all entity object to release memory

        Sleep( 10000 ); //Each 10 second we do it //TODO in future, make this configurable
    }

    //return 0;
}

bool StartWith( const std::string& left, const std::string& right )
{
    auto lit = left.begin();
    auto rit = right.begin();
    
    while( lit != left.end() && rit != right.end() &&  *rit == *lit )
    {
        rit++;
        lit++;
    }

    if( rit != right.end() )
        return false;

    return true;    
}



int main()
{
    //Start the working thread
    _beginthread( (void (_cdecl *)(void*) )WorkingThread, 1024 * 1024, NULL ); 
    
    std::string command;
    command.resize( 1024 );
    while( true )
    {
        std::cin.getline( &command[0], command.size() );

        if( StartWith( command, "quit" ) || StartWith( command, "exit" ) )
        {
            isstopping = true;
            break;
        }
    }

    std::cout << "Closing.....";
    Sleep( 3000 ); //Sleep 3 seconds 

    
}

